package com.cltech.frame.base;

import com.cltech.frame.query.SmartQueryLookupStrategy;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.QueryLookupStrategy;

import javax.persistence.EntityManager;
import java.io.Serializable;
import java.util.Optional;

/**
 * 基础Dao工厂.
 *
 * @param <R> ResponseBean
 * @param <T> T
 * @param <I> I
 * @author guanbo
 * 2018/03/14
 */
public class BaseRepositoryFactoryBean<R extends JpaRepository<T, I>, T,
        I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {

    /**
     * 构造方法. jpa1.11.
     * @param repositoryInterface 基础repository
     */
    public BaseRepositoryFactoryBean(final Class<? extends R> repositoryInterface) {
    super(repositoryInterface);
    }

    /**
     * 接到factory之后，把factory扔了spring data jpa.
     *
     * @param entityManager entityManager
     * @return repositoryFactorySupport
     */
    @Override
    protected RepositoryFactorySupport createRepositoryFactory(final EntityManager entityManager) {
        final RepositoryFactorySupport factorySupport = new BaseRepositoryFactory(entityManager);
        factorySupport.setRepositoryBaseClass(BaseRepositoryImpl.class);
        return factorySupport;
    }

    /**
     * 创建一个内部类，该类不用在外部访问,将我们的baseReposity的实现类扔给factorybean.
     *
     * @param <T> T
     * @param <I> I
     */
    private static class BaseRepositoryFactory<T, I extends Serializable>
            extends JpaRepositoryFactory {
        /**
         * EntityManager.
         */
        private final EntityManager entityManager;
        /**
         * PersistenceProvider.
         */
        private final PersistenceProvider extractor;

        /**
         * BaseRepositoryFactory.
         *
         * @param entityManager EntityManager
         */
        BaseRepositoryFactory(final EntityManager entityManager) {
            super(entityManager);
            this.entityManager = entityManager;
            this.extractor = PersistenceProvider.fromEntityManager(entityManager);
        }
        /**
         * 设置具体的实现类的class.
         * @param metadata metadata
         * @return RepositoryBase
         */
        @Override
        protected Class<?> getRepositoryBaseClass(final RepositoryMetadata metadata) {
            return BaseRepositoryImpl.class;
        }
        @Override
        protected Optional<QueryLookupStrategy> getQueryLookupStrategy(final QueryLookupStrategy.Key key,
                                                                       final EvaluationContextProvider
                                                                     evaluationContextProvider) {
            return Optional.of(SmartQueryLookupStrategy.create(entityManager, key, extractor,
                    evaluationContextProvider));
        }
    }

}
